/*
 * Copyright 2007 - The JDPF Project Team (http://www.jdpf.org) 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package org.jdpf.plugins.file.generator.rgbimage.imagedirectorygenerator;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

import org.jdpf.core.kernel.elements.Token;
import org.jdpf.core.plugins.blocks.AbstractGeneratorPlugin;
import org.jdpf.core.plugins.datatypes.AbstractDataType;
import org.jdpf.core.plugins.exceptions.PluginException;
import org.jdpf.core.plugins.exceptions.PluginExceptionsEnum;
import org.jdpf.plugins.datatypes.media.RGBImage;

/**
 * @author Bruno Farina
 *
 */
public class ImageDirectoryGenerator extends AbstractGeneratorPlugin {
	
	private static final String[] EXTENSIONS={"jpg","jpeg","png","gif"};
	
	private URI _imageSource;

	public ImageDirectoryGenerator(String transitionId, String transitionName) {
		super(transitionId, transitionName);
	}

	@Override
	public Token process(List<Token> list) throws PluginException {
		List<AbstractDataType> outList=null;
		String schema=_imageSource.getScheme();
		if(schema.equalsIgnoreCase("file")){
			File in=new File(_imageSource);
			if(!in.isDirectory()){
				this.log(this, "Reading image file: "+ in.getAbsolutePath());
				outList=readFile(in);
			}else{
				this.log(this, "Reading image from directory: "+ in.getAbsolutePath());
				outList=readDirectory(in);
			}
		}else if(schema.equalsIgnoreCase("http")){
			this.log(this, "Trying to read image from remote: "+ _imageSource);
			if(canBeRead(_imageSource.toString())){
				try {
					InputStream stream=_imageSource.toURL().openStream();
					outList=readFile(stream);
				} catch (MalformedURLException e) {
					throw new PluginException(PluginExceptionsEnum.ExecutionError,this.getPluginId(),
							"The URL "+_imageSource+" is malformed.");
				} catch (IOException e) {
					throw new PluginException(PluginExceptionsEnum.ExecutionError,this.getPluginId(),
							"Unable to open the connection with "+_imageSource.getHost()+".");
				}
			}else
				throw new PluginException(PluginExceptionsEnum.IllegalParameter,this.getPluginId(),
						"The given resource "+_imageSource+" cannot be read by this block.");
		}else
			throw new PluginException(PluginExceptionsEnum.IllegalParameter,this.getPluginId(),
					"Protocol '"+schema+"' not allowed.");
		Token outToken=new Token();
		outToken.setValueList(outList);
		return outToken;
	}

	private List<AbstractDataType> readDirectory(File in) throws PluginException{
		File[] imageFiles=in.listFiles();
		double tot=0.0;
//		Total size calculation loop
		for(int i=0;i<imageFiles.length;i++){
			if(canBeRead(imageFiles[i].getName())){
				tot+=imageFiles[i].length();
			}else{
				this.log("Skipped file "+imageFiles[i].getAbsolutePath());
			}
		}
//		Image files reading loop
		int i=0;
		int j=0;
		List<AbstractDataType> outList=new ArrayList<AbstractDataType>(5);
		while(i<imageFiles.length&&start){
			if(!imageFiles[i].isDirectory()&&canBeRead(imageFiles[i].getName())){
				String ext=getExtension(imageFiles[i].getName());
				BufferedImage image=readImage(imageFiles[i],ext);
				int w=image.getWidth();
				int h=image.getHeight();
				int[] img=image.getRGB(0,0,w,h,null,0,w);
				String fileName=imageFiles[i].getName().substring(0,imageFiles[i].getName().lastIndexOf('.'));
				RGBImage data=new RGBImage(img,w,h,fileName);
				outList.add(j,data);
				j++;
				percentage=Math.min(100.0, percentage+(imageFiles[i].length()+1)/tot*100);
				this.log(this, "Image "+imageFiles[i].getAbsolutePath()+" successfully read.");
			}else{
				this.log(this, "Skipped file "+imageFiles[i].getAbsolutePath());
			}
			i++;
		}
		return outList;
	}

	private List<AbstractDataType> readFile(Object in) throws PluginException{
		String ext=getExtension(_imageSource.toString());
		BufferedImage image=readImage(in,ext);
		int w=image.getWidth();
		int h=image.getHeight();
		double tot=w*h;
		int[] img=new int[w*h];
//		Loop to scan image rows and save pixel value		
		for(int i=0;i<h&&start;i++){
			for(int j=0;j<w&&start;j++){
				img[i*w+j]=image.getRGB(j,i);
				percentage=Math.min(100.0,(((i+1)*w)+j+1)/tot*100);
			}
		}
		String path=_imageSource.toString();
		String fileName=path.substring(path.lastIndexOf("/")+1,path.lastIndexOf('.'));
		RGBImage data=new RGBImage(img,w,h,fileName);
		List<AbstractDataType> outList=new ArrayList<AbstractDataType>(2);
		outList.add(data);
		return outList;
	}
	
	private BufferedImage readImage(Object imageFile,String ext) throws PluginException{
		Iterator<ImageReader> iter=ImageIO.getImageReadersByFormatName(ext);
		ImageReader reader=null;
		if(iter.hasNext()){
			reader=iter.next();
		}
		BufferedImage image=null;
		try {
			ImageInputStream inStream=ImageIO.createImageInputStream(imageFile);
			reader.setInput(inStream);
			image=reader.read(0);
		} catch (IOException e1) {
			throw new PluginException(
					PluginExceptionsEnum.ExecutionError,
					this.getPluginId(),
					"Unable to read image file "+imageFile);
		}
		return image;
	}

	private boolean canBeRead(String name) {
		String ext=name.substring(name.lastIndexOf(".")+1).toLowerCase();
		boolean flag=true;
		for(int i=0;i<EXTENSIONS.length;i++){
			flag=flag&!ext.equals(EXTENSIONS[i]);
		}
		return !flag;
	}
	
	private String getExtension(String name) {
		return name.substring(name.lastIndexOf(".")+1);
	}

	public void setImageSource(URI imageSource) {
		this._imageSource = imageSource;
	}

}
